home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1993…ch: Other People's Memory / ADC Developer CD (1993-03) (''Other People's Memory'')_iso / Dev.CD Mar 93.iso / Technical Documentation / Sample Code / DTS_SCSI Code (In Development) / DTS_SCSI_Install.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-15  |  10.4 KB  |  331 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        Install.c
  3.     
  4.     
  5.     
  6.     
  7.     
  8.     Unfortunately, no matter how long awaited, it's still not done.  In fact, this
  9. isn't even a release- this is just an image of the code taken in the middle of
  10. development.
  11.  
  12. THIS CODE DOES NOT WORK AS A WHOLE.  MUCH OF IT IS BUGGY AND / OR INCOMPLETE.
  13. YOU WOULD HAVE TO BE ABSOLUTELY INSANE TO USE ANY OF THIS CODE IN YOUR
  14. PROJECT WITHOUT EXTENSIVE THOUGHT, DEBUGGING AND TESTING.
  15.  
  16.  
  17.  
  18.  
  19.  
  20.  
  21.     Contains:    SCSI driver installation code
  22.  
  23.     Written by:    Craig Prouse
  24.  
  25.     Copyright:    © 1991-1992 by Apple Computer, Inc., all rights reserved.
  26.  
  27.     Change History (most recent first):
  28.          <7>     4/24/92    tmd        Changes based on new TDriveVars structure
  29.          <6>     4/22/92    khs        Fixes based on the code review, removed old partition map code
  30.                                      (not really needed anymore)
  31.          
  32.          <5>      3/6/92    chp        Fix a bug in ValidOldPartition where pdFSID was being tested for
  33.                                     nonzero rather than zero.
  34.          <4>    11/26/91    chp        fix bugs: look for an open unit to install into rather than an
  35.                                     occupied unit (logic was reversed), and set the correct bit in
  36.                                     the dCtlFlags word to get an accRun call (was setting the
  37.                                     correct bit in the wrong byte)
  38.          <3>    11/25/91    chp        rewrite InstallProc from scratch and add numerous supporting
  39.                                     subroutines and data structures
  40.          <2>    10/17/91    chp        modify so that project builds correctly and add debug code
  41.          <1>    10/17/91    chp        first checked in
  42.  
  43.     To Do:
  44. */
  45.  
  46. #define __FILE_NUMBER__        0x3000
  47.  
  48. #include    <Types.h>
  49. #include    <Traps.h>
  50. #include    <Memory.h>
  51. #include    <SysEqu.h>
  52. #include    <Devices.h>
  53. #include    <SCSI.h>
  54. #include    <string.h>
  55. #include    <PLStringFuncs.h>
  56. #include    "DTS_SCSI_Driver.h"
  57. #include    "DTS_SCSI_Debug.h"
  58.  
  59.  
  60. #define        HiByte(a)        (*(char *) &(a))
  61.  
  62.  
  63. // bits in dCtlFlags
  64. enum {
  65.     dOpened = 5,
  66.     dRAMBased,
  67.     drvrActive
  68. };
  69.  
  70. // base for SCSI device unit numbers; unit number = base + SCSI ID
  71. #define    kSCSIUnitBase 32
  72.  
  73. struct DriverHeader {
  74.     short    drvrFlags;
  75.     short    drvrDelay;
  76.     short    drvrEMask;
  77.     short    drvrMenu;
  78.     short    drvrOpen;
  79.     short    drvrPrime;
  80.     short    drvrCtl;
  81.     short    drvrStatus;
  82.     short    drvrClose;
  83.     Str255    drvrName;
  84. };
  85. typedef struct DriverHeader DriverHeader;
  86.  
  87. // DrvrHdr is an imported assembly language label for the driver's header
  88. extern DriverHeader DrvrHdr;
  89.  
  90. extern Boolean BlindIsSafe (void);
  91. extern Boolean IsBootTime (void);
  92.  
  93. static void SetPartition (TDriveVars *vars, Partition *partitionMap);
  94. static void    InitPartitionVars (TDriveVars *vars, long partitionOffset, long partitionSize);
  95. static void RemoveDupDriver(short sourceUnit);
  96. static void ReplaceDriver(DCtlPtr dce,DriverHeader *newDriver);
  97. static Boolean     ValidPartitionMap (Partition *pm);
  98. static Boolean     HFSPartition (Partition *pm);
  99.  
  100. #pragma parameter __D0 DriverInstall (__A0, __D0)
  101. static OSErr DriverInstall (Ptr drvrPtr, short refNum) = {_DrvrInstall};
  102.  
  103. #pragma parameter __D0 DriverRemove (__D0)
  104. static OSErr DriverRemove (short refNum) = {_DrvrRemove};
  105.  
  106. void InstallProc (Partition *partitionMap, short scsiID, Ptr sbData) {
  107.     #pragma unused (sbData)
  108.         
  109.     DCtlPtr            dce;
  110.     DriverHeader    *pDriver;
  111.     TDriveVars        *vars;
  112.     short            unit, refNum, ignoreRefNum;
  113.     OSErr            instErr;
  114.     
  115.     unit = kSCSIUnitBase + scsiID;
  116.     refNum = ~unit;
  117.     pDriver = &DrvrHdr;
  118.     
  119.     if (GetDCtlEntry(refNum) == nil) {
  120.  
  121.         //
  122.         //    _DrvrInstall allocates a DCtlHandle, places it in the unit table, and
  123.         //    stores the indicated refNum in the dCtlRefNum field.  That's all it does.
  124.         //
  125.         instErr = DriverInstall((Ptr) pDriver, refNum);
  126.         
  127.         if (instErr == noErr) {
  128.             // copy driver's header information into the DCE
  129.             
  130.             // *** Why don't we use GetDCtlEntry here ?
  131.             dce = *(*(DCtlHandle **) UTableBase)[unit];
  132.             dce->dCtlDriver = (Ptr) pDriver;
  133.             dce->dCtlFlags = pDriver->drvrFlags & ~(1 << dRAMBased);
  134.             dce->dCtlDelay = pDriver->drvrDelay;
  135.             dce->dCtlEMask = pDriver->drvrEMask;
  136.             dce->dCtlMenu = pDriver->drvrMenu;
  137.             
  138.             // driver is all installed, so now open it
  139.             instErr = OpenDriver(pDriver->drvrName, &ignoreRefNum);
  140.             if (instErr == noErr) {
  141.                 vars = *(TDriveVars **) dce->dCtlStorage;
  142.                 vars->driveID = scsiID;                        // save the drive's SCSI bus ID
  143.                 vars->driveBlockSize = 512;                    // this is an assumption
  144.                 vars->blindOK = BlindIsSafe();
  145.                 
  146.                 SetPartition(vars, partitionMap);
  147.                 
  148.                 //
  149.                 //    There are a couple of details to attend to at boot time.
  150.                 //    
  151.                 //        - make sure we get an accRun callback
  152.                 //        - defer enabling blind reads where appropriate
  153.                 //
  154.                 //    At the callback, a disk insertion event will be posted if necessary
  155.                 //    and we will reconsider whether to enable blind transfers if we don't
  156.                 //    choose to enable them at this time.
  157.                 //
  158.                 if (IsBootTime()) {
  159.                     dce->dCtlFlags |= (dNeedTime << 8);        // Change the high byte
  160.                     dce->dCtlDelay = 0;                        // right away
  161.                     
  162.                     // assume the file system doesn't see us until it proves otherwise
  163.                     vars->tickleFlag = true;
  164.                 }
  165.             
  166.             // remove duplicate copies of our driver
  167.             RemoveDupDriver(unit);
  168.             
  169.             }
  170.             else {
  171.                 DriverRemove(refNum);
  172.                 
  173.                 //
  174.                 //    The SCSI Development Package 1.0 (dated 1986) here calls DisposPtr
  175.                 //    on the pointer containing the disk driver code.  While this has
  176.                 //    worked, there could be problems related to this call.  It is probably better to 
  177.                 //  just leave the driver's rotting corpse in the system heap. Note that this
  178.                 //  case will only happen the first time we install the driver.
  179.                 //
  180.             
  181.             }
  182.         }
  183.     }
  184. }
  185.  
  186.  
  187. //
  188. // Remove duplicate copies of the driver.  This routine searches through the
  189. // unit table for device entries which have the same driver name and version
  190. // as our driver and removes them, replacing them with references to our
  191. // driver.  We only replace exact copies of our driver, because we can't
  192. // be certain we'll be compatible otherwise.
  193. //
  194. // Doing this saves us memory at runtime but it means we can't use code-
  195. // relative storage for static storage, since a driver may be shared
  196. // among several drives.
  197. //
  198. // The passed unit number indicates which driver to compare the others
  199. // to and to replace them with, and should be the unit number of the
  200. // driver we are currently installing.
  201. //
  202.  
  203. static void RemoveDupDriver(short sourceUnit)
  204. {    DCtlHandle        *unitTable,dceH;
  205.     DCtlPtr            dce;
  206.     short            unit;
  207.     unsigned char    *version;
  208.     DriverHeader    *driver,*sourceDriver;
  209.     
  210.     unitTable = *(DCtlHandle **)UTableBase;
  211.     
  212.     // Loop through valid SCSI device driver unit numbers
  213.     
  214.     sourceDriver = (DriverHeader*) (*(unitTable[sourceUnit]))->dCtlDriver;
  215.     
  216.     for (unit = kSCSIUnitBase + 1;unit < kSCSIUnitBase + 7;unit++)
  217.     {    if (unit != sourceUnit)
  218.         {    dceH = unitTable[unit];
  219.         
  220.             if (dceH)
  221.             {    dce = *dceH;
  222.                 // Our driver is always referred to by a pointer
  223.                 if (dce && !(dce->dCtlFlags & (1 << dRAMBased)))
  224.                 {    driver = (DriverHeader*)dce->dCtlDriver;
  225.                     if (PLstrcmp(driver->drvrName,kDriverName) == 0)    // Does the name match?
  226.                     {    // The version number byte is packed in immediately after the name
  227.                         version = driver->drvrName;        // Point at the name
  228.                         version += *version + 1;        // Advance by length + 1
  229.                         if (*version == kCurrentDriverVersion)    // Does the version match?
  230.                             // Everything matches, so replace the driver with ourselves
  231.                             ReplaceDriver(dce,sourceDriver);
  232.                     }
  233.                 }
  234.             }
  235.         }
  236.     }
  237. }
  238.  
  239.  
  240. //
  241. // Replace the driver referred to in a DCE with another driver.  This assumes
  242. // that the DCE has a driver which conforms to our standard of having a long
  243. // just before the driver header which tells how many bytes into the driver's
  244. // memory manager block the driver header is; this allows us to back up to
  245. // find the start of the block so we can dispose of it.  We also replace the
  246. // driver reference in the DCE with the new driver.
  247. //
  248.  
  249. static void ReplaceDriver(DCtlPtr dce,DriverHeader *newDriver)
  250. {    long            offset;
  251.     Ptr                driverBlock;
  252.     DriverHeader    *oldDriver;
  253.     
  254.     oldDriver = (DriverHeader*) dce->dCtlDriver;
  255.     
  256.     // Replace the old driver reference with a pointer to the new driver; doing
  257.     // this first makes the driver always valid (rather than disposing, then
  258.     // replacing), plus it makes sure that we can't move the DCtlEntry, which
  259.     // we might have an unstable pointer to, should DisposPtr ever start to
  260.     // move memory.
  261.     
  262.     dce->dCtlDriver = (Ptr)newDriver;
  263.     
  264.     offset = *(((long*)oldDriver) - 1);            // Offset is one long back from driver
  265.     driverBlock = ((Ptr)oldDriver) - offset;    // Back up to start of block
  266.     
  267.     // Now that we've got the start of the block, we need to deallocate the pointer
  268.     // block.  Theoretically, the driver could have been allocated in a locked
  269.     // handle, but we're now requiring that anyone who loads arbitrary drivers
  270.     // load them into a pointer block in the System heap.  Thus, we assume that
  271.     // we've now got a pointer to a Ptr block, and we'll just dispose of it.
  272.         
  273.     DisposPtr(driverBlock);                        // Dispose of old driver block
  274. }
  275.  
  276.  
  277. static void SetPartition (TDriveVars *vars, Partition *partitionMap) {
  278.     //
  279.     //    Search the available partition map for an HFS partition.  Only the new (IMV5)
  280.     //    partition map format are supported.  If no partition map is found, no operation
  281.     //    is performed.  The result is that the partition offset and size are left set
  282.     //    to zero in the drive variables and drive queue.  This effectively disables the
  283.     //    driver from performing reads or writes since these are restricted to a valid
  284.     //    partition.
  285.     //
  286.     if (partitionMap != nil) {
  287.         if (ValidPartitionMap(partitionMap)) {
  288.             //
  289.             //    This is the partition map format documented in Inside Macintosh,
  290.             //    Volume V.  This is the preferred implementation, and the one for
  291.             //    which interfaces are predefined.
  292.             //
  293.             while (ValidPartitionMap(partitionMap) && !HFSPartition(partitionMap)) {
  294.                 // scan partition map entries for one with an HFS file system ID
  295.                 partitionMap++;
  296.             }
  297.             if (ValidPartitionMap(partitionMap)) {
  298.                 // found an HFS partition: fill in drive variables
  299.                 InitPartitionVars(vars, partitionMap->pmPyPartStart, partitionMap->pmPartBlkCnt);
  300.             }
  301.         }
  302.     }
  303. }
  304.  
  305.  
  306. static void InitPartitionVars (TDriveVars *vars, long partitionOffset, long partitionSize) {
  307.     vars->partitionOffset = partitionOffset;
  308.     
  309.     // finish initializing the drive queue element
  310.     vars->driveQElem.elem.dQDrvSz = partitionSize;                // low word
  311.     vars->driveQElem.elem.dQDrvSz2 = partitionSize >> 16;        // high word
  312. }
  313.  
  314.  
  315. static Boolean ValidPartitionMap (Partition *pm) {
  316.     //
  317.     //    This is a very simple routine but it is called from several places.
  318.     //    It's broken out separately for ease of maintenance.
  319.     //
  320.     return pm->pmSig == pMapSIG;
  321. }
  322.  
  323.  
  324. static Boolean HFSPartition (Partition *pm) {
  325.     const char *hfsID = "Apple_HFS";
  326.     const size_t kPartTypeSize = 32;
  327.     
  328.     return strncmp(pm->pmParType, hfsID, kPartTypeSize) == 0;
  329. }
  330.  
  331.